package com.tn.rtdata.examples.stockticker;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Random;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

/**
 * A stock tick domain object.
 */
public class StockTick implements Serializable
{
  public static final int DEFAULT_SCALE = 2;

  private String stockId;
  private BigDecimal price;
  private Random random = new Random();

  /**
   * Creates a new <code>StockTick</code>.
   */
  public StockTick(String stockId)
  {
    this(stockId, randomPrice());
  }

  /**
   * Creates a new <code>StockTick</code>.
   */
  public StockTick(String stockId, BigDecimal price)
  {
    this.stockId = stockId;
    this.price = price;
  }

  /**
   * Returns the price.
   */
  public BigDecimal getPrice()
  {
    return price;
  }

  /**
   * Returns the stock id.
   */
  public String getStockId()
  {
    return stockId;
  }

  /**
   * Compares this object to another for equality.  For another object to be considered equal to a <code>StockTick</code> the other
   * object must be a <code>StockTick</code> and must have been initialized with the same values.
   *
   * @param other the other object.
   *
   * @return <code>true</code> if the objects are considered equal, otherwise <code>false</code>.
   */
  @Override
  public boolean equals(Object other)
  {
    return this == other || other != null && getClass() == other.getClass() &&
      new EqualsBuilder()
        .append(getStockId(), ((StockTick)other).getStockId())
        .append(getPrice(), ((StockTick)other).getPrice())
        .isEquals();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public int hashCode()
  {
    return new HashCodeBuilder()
      .append(getStockId())
      .append(getPrice())
      .toHashCode();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public String toString()
  {
    return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
      .append("stockId", getStockId())
      .append("price", getPrice())
      .toString();
  }

  /**
   * Returns a new <code>StockTick</code> based on this <code>StockTick</code> with a price moved by a random amount that will be no greater
   * than the <code>maximumMovementPercentage</code>.
   */
  public StockTick movePrice(BigDecimal maximumMovementPercentage)
  {
    BigDecimal percentageMove = maximumMovementPercentage.multiply(new BigDecimal(Math.random())).setScale(
      StockTick.DEFAULT_SCALE,
      BigDecimal.ROUND_HALF_UP
    );

    BigDecimal priceChange = getPrice().multiply(percentageMove.divide(new BigDecimal("100")));

    if (random.nextBoolean())
    {
      return new StockTick(
        getStockId(),
        getPrice().add(priceChange).setScale(StockTick.DEFAULT_SCALE, BigDecimal.ROUND_HALF_UP)
      );
    }
    else
    {
      return new StockTick(
        getStockId(),
        getPrice().subtract(priceChange).setScale(StockTick.DEFAULT_SCALE, BigDecimal.ROUND_HALF_UP)
      );
    }
  }


  /**
   * Returns a random price.
   */
  private static BigDecimal randomPrice()
  {
    return new BigDecimal(Math.random() * 100).setScale(DEFAULT_SCALE, BigDecimal.ROUND_HALF_UP);
  }
}
